#!/usr/bin/env python3
# Ensure the above line is the very first line of your script
# and that the script has execute permissions: chmod +x your_script_name.py

import requests
import json
import os
from dotenv import load_dotenv

# Load environment variables from .env file
# This will load variables like CF_API_KEY, CF_EMAIL, CF_ZONE_ID from your .env file
load_dotenv()

# --- Configuration ---
# Cloudflare API Key, Email, and Zone ID are now loaded from the .env file or system environment variables.
CF_API_KEY = os.environ.get("CF_API_KEY")
CF_EMAIL = os.environ.get("CF_EMAIL")
CF_ZONE_ID = os.environ.get("CF_ZONE_ID") # Used as default, can be overridden by user input

# Cloudflare API base URL
CF_API_BASE_URL = "https://api.cloudflare.com/client/v4"

def get_cloudflare_headers():
    """
    Returns the standard headers required for Cloudflare API requests.
    """
    # --- DEBUGGING PRINT ---
    # print(f"DEBUG: Using CF_EMAIL: {CF_EMAIL}")
    # print(f"DEBUG: Using CF_API_KEY: {'*' * len(CF_API_KEY) if CF_API_KEY else 'None'}") # Mask API key for safety

    if not all([CF_API_KEY, CF_EMAIL]):
        print("Error: Cloudflare API Key or Email is not set. Please set CF_API_KEY and CF_EMAIL environment variables or define them in the script or in a .env file.")
        exit(1)

    return {
        "X-Auth-Email": CF_EMAIL,
        "X-Auth-Key": CF_API_KEY,
        "Content-Type": "application/json"
    }

def get_all_dns_records(zone_id):
    """
    Fetches all DNS records for a given Cloudflare zone ID, handling pagination.
    """
    if not zone_id:
        print("Error: Cloudflare Zone ID is not provided.")
        return []

    # --- DEBUGGING PRINT ---
    # print(f"DEBUG: Attempting to fetch records for Zone ID: {zone_id}")

    url = f"{CF_API_BASE_URL}/zones/{zone_id}/dns_records"
    headers = get_cloudflare_headers()
    all_records = []
    page = 1
    per_page = 100 # Maximum allowed per_page by Cloudflare API

    print(f"Fetching DNS records for Zone ID: {zone_id}...")

    while True:
        params = {"page": page, "per_page": per_page}
        try:
            response = requests.get(url, headers=headers, params=params)
            response.raise_for_status() # Raise an HTTPError for bad responses (4xx or 5xx)
            data = response.json()

            if data["success"]:
                records_on_page = data["result"]
                all_records.extend(records_on_page)

                # Check if there are more pages
                total_pages = data["result_info"]["total_pages"]
                print(f"  Fetched page {page}/{total_pages} ({len(records_on_page)} records). Total records collected so far: {len(all_records)}")

                if page < total_pages:
                    page += 1
                else:
                    break # No more pages
            else:
                # --- DEBUGGING PRINT ---
                # print(f"DEBUG: Cloudflare API response (success=false): {data}")
                print(f"Error fetching DNS records for page {page}: {data['errors']}")
                return [] # Return empty list on error
        except requests.exceptions.RequestException as e:
            # --- DEBUGGING PRINT ---
            if hasattr(e, 'response') and e.response is not None:
                print(f"DEBUG: Full error response content: {e.response.text}")
            print(f"Network error fetching DNS records on page {page}: {e}")
            return []
        except Exception as e:
            print(f"An unexpected error occurred while fetching DNS records on page {page}: {e}")
            return []

    return all_records

def main():
    """
    Main function to get and display all DNS records in a table format.
    """
    if not all([CF_API_KEY, CF_EMAIL]):
        print("Please ensure CF_API_KEY and CF_EMAIL environment variables are set (either in your system or in a .env file in the script's directory).")
        print("Example .env content:")
        print("CF_API_KEY=\"your_key\"")
        print("CF_EMAIL=\"your_email\"")
        print("CF_ZONE_ID=\"your_zone_id\"")
        return

    zone_id_to_use = CF_ZONE_ID
    if not zone_id_to_use:
        zone_id_to_use = input("Enter the Cloudflare Zone ID to list DNS records for: ").strip()
        if not zone_id_to_use:
            print("Zone ID cannot be empty. Exiting.")
            return

    # --- DEBUGGING PRINT ---
    # print(f"DEBUG: Zone ID being used for request: {zone_id_to_use}")

    dns_records = get_all_dns_records(zone_id_to_use)

    if dns_records:
        print(f"\n--- All DNS Records for Zone ID: {zone_id_to_use} ({len(dns_records)} records) ---")

        # Define column widths (adjust as needed for your data)
        # Max lengths seen so far + some padding
        max_type_len = max(len(record.get('type', '')) for record in dns_records) if dns_records else 4
        max_name_len = max(len(record.get('name', '')) for record in dns_records) if dns_records else 4
        max_content_len = max(len(record.get('content', '')) for record in dns_records) if dns_records else 7
        max_ttl_len = max(len(str(record.get('ttl', ''))) for record in dns_records) if dns_records else 3

        # Add padding to column widths, minimums for headers
        type_width = max(max_type_len, len("TYPE")) + 2
        name_width = max(max_name_len, len("NAME")) + 2
        content_width = max(max_content_len, len("CONTENT")) + 2
        ttl_width = max(max_ttl_len, len("TTL")) + 2
        proxied_width = len("PROXIED") + 2 # Boolean, fixed size

        # Print table header
        header = (
            f"{'TYPE':<{type_width}}"
            f"{'NAME':<{name_width}}"
            f"{'CONTENT':<{content_width}}"
            f"{'TTL':<{ttl_width}}"
            f"{'PROXIED':<{proxied_width}}"
        )
        print(header)
        print("-" * len(header))

        # Print each record
        for record in dns_records:
            record_type = record.get('type', 'N/A')
            record_name = record.get('name', 'N/A')
            record_content = record.get('content', 'N/A')
            record_ttl = record.get('ttl', 'N/A')
            record_proxied = "Yes" if record.get('proxied') else "No"

            # Truncate content if it's too long
            if len(record_content) > content_width - 2:
                record_content = record_content[:content_width - 5] + "..." # -5 to account for "..." and a bit of space

            row = (
                f"{record_type:<{type_width}}"
                f"{record_name:<{name_width}}"
                f"{record_content:<{content_width}}"
                f"{str(record_ttl):<{ttl_width}}"
                f"{record_proxied:<{proxied_width}}"
            )
            print(row)
    else:
        print(f"No DNS records found or an error occurred for Zone ID: {zone_id_to_use}.")

if __name__ == "__main__":
    main()
